/*
 * Copyright 2003-2007 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

package com.colony.networkvm.machine;

import java.util.ArrayList;
import java.util.List;

import com.argot.TypeException;
import com.argot.TypeLibrary;
import com.colony.networkvm.NvmEnvironment;
import com.colony.networkvm.instruction.NvmInstruction;
import com.colony.networkvm.instruction.NvmReturn;
import com.colony.remote.RemoteException;

public class NvmInstance
{
    public static String TYPENAME = "NetworkVM";
	
    // local on the host machine.
	private NvmEnvironment _environment;
	private TypeLibrary _library;
	
	// items moved between systems.
	private List _instructions;
	private int _programCounter;
	private NvmHeap _heap;
	private NvmStack _stack;
	private Throwable _exception;

	public NvmInstance(NvmEnvironment env, TypeLibrary library,NvmState state)
	{
		_environment = env;
		_library = library;
		_stack = new NvmStack();
		
		_instructions = state._instructions;
		_programCounter = state._programCounter;
		_heap = state._heap;
		_exception = state._exception;
	}

	public NvmInstance( NvmEnvironment env, TypeLibrary library )
	{
		_environment = env;
		_library = library;
		_stack = new NvmStack();
		
		_instructions = new ArrayList();
		_heap = new NvmHeap();
		_programCounter = 0;	
		_exception = null;	
	}

	public void setState( NvmState state )
	{
		_instructions = state._instructions;
		_programCounter = state._programCounter;
		_heap = state._heap;
		_exception = state._exception;
	}

	public NvmState getState()
	{
		NvmState state = new NvmState();
		state._instructions = _instructions;
		state._programCounter = _programCounter;
		state._heap = _heap;
		state._exception = _exception;
		return state;
	}
	

	// host methods.
	
	public NvmEnvironment getEnvironment()
	{
		return _environment;
	}


	public TypeLibrary getTypeLibrary()
	{
		return _library;
	}
	
	

	public void push( Object o )
	throws RemoteException
	{
		_stack.push( -1, o );
	}

	public void push( int id, Object o )
	{
		_stack.push( id, o );
	}

	public Object pop( )
	{
		return _stack.pop();
	}

	public Object peek()
	{
		return _stack.peek();
	}
	
	public int peekId()
	{
		return _stack.peekId();
	}
	
	public boolean isEmpty()
	{
		return _stack.empty();
	}
	
	// Heap functions.
	public Object getHeapObject( int index ) 
	throws RemoteException
	{
		return _heap.getObject( index );
	}
	
	public int addHeapObject( int id, Object o )
	{
		return _heap.addObject( id, o );
	}
	
	public int addHeapObject( String name, Object o ) 
	throws RemoteException
	{
		int i;

		try 
		{
			i= _library.getId( name );
		}
		catch (TypeException e) 
		{
			e.printStackTrace();
			throw new RemoteException( "Type not found "+name );
		}
					
		return _heap.addObject(i, o );
	}
	
	public Object removeHeapObject( int index ) 
	throws RemoteException
	{
		return _heap.removeObject( index );
	}	
	
	// exception handling.
	public void setException( Throwable ex )
	{
		_exception = ex;
	}
	
	public boolean hasException()
	{
		return _exception == null ? false : true;
	}
	
	public Throwable getException()
	{
		return _exception;
	}

	// instructions
 
	public void addInstruction( NvmInstruction instruction )
	{
		_instructions.add( instruction );
	}
	
	public void execute(NvmInstance request) 
	throws RemoteException
	{
		int index = request.getProgramCounter();
		       
		while ( index != -1 )
		{
			NvmInstruction instruction = (NvmInstruction) _instructions.get(index);
			if ( instruction instanceof NvmReturn )
			{
				return;
			}
			instruction.execute(request);
			if ( request.hasException() )
			{
				return;
			}
			index = request.getProgramCounter();
		}
        
	}

    private int getProgramCounter()
    {
        
        return _programCounter;
    }
    
    public void incProgramCounter()
    {
    	_programCounter++;
    }

 
    public void storeHeapObject(int index, int id, Object o)
    {
        _heap.storeHeapObject( index, id, o);
        
    }
    	
}
